//
//  RetryPlugin.swift
//  XNetwork
//
//  Created by x on 2024/8/19.
//

import Moya

// 重试配置
public struct RetryConfiguration {
    let maxRetryCount: Int       // 最大重试次数
    let initialDelay: TimeInterval // 初始重试间隔
    let backoffFactor: Double      // 指数退避增长因子
    
    init(maxRetryCount: Int = 3, initialDelay: TimeInterval = 1.0, backoffFactor: Double = 2.0) {
        self.maxRetryCount = maxRetryCount
        self.initialDelay = initialDelay
        self.backoffFactor = backoffFactor
    }
}

// 自定义重试插件
public final class RetryPlugin: PluginType {
    
    private let retryConfiguration: RetryConfiguration
    
    init(retryConfiguration: RetryConfiguration = RetryConfiguration()) {
        self.retryConfiguration = retryConfiguration
    }
    
    public func didReceive(_ result: Result<Response, MoyaError>, target: TargetType) {
        guard case .failure(let error) = result else { return }
        
        handleRetry(for: error, target: target, currentRetryCount: 0)
    }
    
    private func handleRetry(for error: MoyaError, target: TargetType, currentRetryCount: Int) {
        guard currentRetryCount < retryConfiguration.maxRetryCount else {
            // 超过最大重试次数
            return
        }
        
        // 检查错误类型和网络状态，决定是否重试
        if shouldRetry(for: error) {
            let delay = retryConfiguration.initialDelay * pow(retryConfiguration.backoffFactor, Double(currentRetryCount))
            
            DispatchQueue.global().asyncAfter(deadline: .now() + delay) { [weak self] in
                guard let self = self else { return }
                self.retryRequest(target: target, currentRetryCount: currentRetryCount + 1)
            }
        }
    }
    
    private func shouldRetry(for error: MoyaError) -> Bool {
        // 根据具体的错误类型和网络状态决定是否重试
        switch error {
        case .underlying(let nsError as NSError, _):
            if nsError.domain == NSURLErrorDomain && (nsError.code == NSURLErrorNotConnectedToInternet || nsError.code == NSURLErrorTimedOut) {
                return true
            }
        default:
            return false
        }
        return false
    }
    
    private func retryRequest(target: TargetType, currentRetryCount: Int) {
        
        target.requset().do(onError: { (error) in
            guard let moyaError = error as? MoyaError else { return }
            // 失败则继续处理重试逻辑
            self.handleRetry(for: moyaError, target: target, currentRetryCount: currentRetryCount)
        })
    }
}

//// 使用示例
//let provider = MoyaProvider<YourTargetType>(plugins: [RetryPlugin()])
//
//provider.request(.yourAPI) { result in
//    switch result {
//    case .success(let response):
//        // 处理成功响应
//        print("Success: \(response)")
//    case .failure(let error):
//        // 处理错误
//        print("Error: \(error)")
//    }
//}
